package jp.sourceforge.akjrcp.text_douga.parser;

import java.awt.Font;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;

import jp.sourceforge.akjrcp.draw.DecoratedShapePainter;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegFLVParser;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegFileInfomation;
import jp.sourceforge.akjrcp.ffmpeg.FFMpegUtils;
import jp.sourceforge.akjrcp.ffmpeg.FLVInfomation;
import jp.sourceforge.akjrcp.text_douga.AudioData;
import jp.sourceforge.akjrcp.text_douga.DougaSystem;
import jp.sourceforge.akjrcp.text_douga.EffectData;
import jp.sourceforge.akjrcp.text_douga.ItemData;
import jp.sourceforge.akjrcp.text_douga.Messages;
import jp.sourceforge.akjrcp.text_douga.VideoData;
import jp.sourceforge.akjrcp.text_douga.audio.FileAudioData;
import jp.sourceforge.akjrcp.text_douga.audio.ZeroAudioData;
import jp.sourceforge.akjrcp.text_douga.effect.FillColorEffect;
import jp.sourceforge.akjrcp.text_douga.effect.FillImageEffect;
import jp.sourceforge.akjrcp.text_douga.effect.FrameImageEffect;
import jp.sourceforge.akjrcp.text_douga.effect.VideoEffect;
import jp.sourceforge.akjrcp.text_douga.item.AbstractItem;
import jp.sourceforge.akjrcp.text_douga.item.ColorItem;
import jp.sourceforge.akjrcp.text_douga.item.GifAnimeItem;
import jp.sourceforge.akjrcp.text_douga.item.ImageItem;
import jp.sourceforge.akjrcp.text_douga.item.TextItem;
import jp.sourceforge.akjrcp.text_douga.video.ColorVideoData;
import jp.sourceforge.akjrcp.text_douga.video.EffectableVideoData;
import jp.sourceforge.akjrcp.text_douga.video.FileVideoData;
import jp.sourceforge.akjrcp.text_douga.video.ImageVideoData;
import jp.sourceforge.akjrcp.util.DownloadUtils;
import jp.sourceforge.akjrcp.util.URLDownloader;
import jp.sourceforge.akjrcp.util.YoutubeUtils;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class SimpleParser {
	public static Log log = LogFactory.getLog(SimpleParser.class);
	private File downloadedDir;
	private String ffmpegPath;//TODO can choose mediainfo
	private String youtubeDLPath;
	private String pythonPath;
	
	PropertyLine propertyLine=null;
	
	private boolean shortest;//TODO
	private DougaSystem dougaSystem;
	private List<VideoData> videoList;
	private List<AudioData> audioList;
	
	//private File inputFile;
	private File inputDir;
	private float default_color_transparent=0.85f;
	
	private List<ItemData> itemList;
	private List<EffectData> effectList;
	
	private double line_duration=0;//zero means same as fps
	
	private double default_color_duration=1;
	
	private double default_text_fadein=0;
	private double default_text_fadeout=0.1;
	private double default_image_fadein=0.1;
	private double default_image_fadeout=0.2;
	
	private int default_image_width=0;
	private int default_image_height=0;
	
	private boolean cancelling;
	
	
	private String font_name="MS Mincho";
	private String font_style=PropertyUtils.FONT_STYLE_PLAIN;
	private int font_size=18;
	private int text_line_color=0xffffff;
	private int text_border_color=0xcccccc;
	private int text_shadow_color=0;
	private int text_border_size=1;
	private int text_shadow_x=2;
	private int text_shadow_y=2;
	private boolean text_antialiase=true;
	private boolean text_draw_line=true;
	private boolean text_draw_border=true;
	private boolean text_draw_shadow;
	
	public SimpleParser(String ffmpegPath){
		this.ffmpegPath=ffmpegPath;
	}
	public SimpleParser(String ffmpegPath,File downloadedDir){
		this(ffmpegPath);
		this.downloadedDir=downloadedDir;
	}
	
	public SimpleParser(String ffmpegPath,File downloadedDir,String pythonPath,String youtubeDLPath){
		this(ffmpegPath,downloadedDir);
		this.pythonPath=pythonPath;
		this.youtubeDLPath=youtubeDLPath;
	}
	
	public void parseProperty() throws IOException{
		boolean consume=false;
		//video parsing
		String video=getProperty(PropertyUtils.VIDEO);
		double duration=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DURATION),DougaSystem.FOREEVER);
		log.info("video="+video);
		VideoData videoData=null;
		if(ParserUtils.isColorText(video)){
			
			int color=ParserUtils.toColor(video);
			
			videoData=new ColorVideoData(color);
			videoData.setDuration(duration);
			videoList.add(videoData);
//			TODO audio=silence
			consume=true;
			log.info(videoData);
		}else if(ParserUtils.getFileType(video)==ParserUtils.FILE_IMAGE){
			String path=ParserUtils.toFilePath(inputDir,video);
			//validate check.
			if(!new File(path).exists()){
				throw new IOException(path +" no found");
			}else{
				log.info("bgfile:"+path);
			}
			//audio..
			videoData=new ImageVideoData(path);
			videoData.setDuration(duration);
			videoList.add(videoData);
			
			consume=true;
			log.info("ImageData added");
		}else{
			//log.warn("unknown video:"+video);
		}
		String audio=getProperty(PropertyUtils.AUDIO);
		log.info("audio="+audio);
		if(audio!=null){
		if(audio.equals(PropertyUtils.SILENCE)){
			ZeroAudioData zero=new ZeroAudioData();
			zero.setDuration(duration);
			if(videoData!=null){
				videoData.setAudioData(zero);
			}
			audioList.add(zero);
			consume=true;
			log.info("silenseData added");
		}
		}
		//TODO show warn
		//novideo
		//noaudio
		//global property
		if(getProperty(PropertyUtils.LINE_FPS)!=null){
			line_fps=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.LINE_FPS),1);
		}
		
		if(getProperty(PropertyUtils.LINE_DURATION)!=null){
			line_duration=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.LINE_DURATION),0);
		}
		
		if(getProperty(PropertyUtils.DEFAULT_TEXT_FADEIN)!=null){
			default_text_fadein=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DEFAULT_TEXT_FADEIN),default_text_fadein);
		}
		
		if(getProperty(PropertyUtils.DEFAULT_TEXT_FADEOUT)!=null){
			default_text_fadeout=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DEFAULT_TEXT_FADEOUT),default_text_fadeout);
		}
		
		if(getProperty(PropertyUtils.DEFAULT_IMAGE_FADEIN)!=null){
			default_image_fadein=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DEFAULT_IMAGE_FADEIN),default_image_fadein);
		}
		
		if(getProperty(PropertyUtils.DEFAULT_IMAGE_FADEOUT)!=null){
			default_image_fadeout=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DEFAULT_IMAGE_FADEOUT),default_image_fadeout);
		}
		
		if(getProperty(PropertyUtils.DEFAULT_COLOR_DURATION)!=null){
			default_color_duration=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DEFAULT_COLOR_DURATION),default_color_duration);
		}
		
		if(getProperty(PropertyUtils.DEFAULT_COLOR_TRANSPARENT)!=null){
			default_color_transparent=PropertyUtils.getFloatValue(getProperty(PropertyUtils.DEFAULT_COLOR_TRANSPARENT),default_color_transparent);
		}
		
		if(getProperty(PropertyUtils.DEFAULT_IMAGE_WIDTH)!=null){
			default_image_width=PropertyUtils.getIntValue(getProperty(PropertyUtils.DEFAULT_IMAGE_WIDTH),default_image_width);
		}
		
		if(getProperty(PropertyUtils.DEFAULT_IMAGE_HEIGHT)!=null){
			default_image_height=PropertyUtils.getIntValue(getProperty(PropertyUtils.DEFAULT_IMAGE_HEIGHT),default_image_height);
		}
		
		
		if(getProperty(PropertyUtils.FONT_NAME)!=null){
			font_name=PropertyUtils.getStringValue(getProperty(PropertyUtils.FONT_NAME),font_name);
		}
		if(getProperty(PropertyUtils.FONT_STYLE)!=null){
			font_style=PropertyUtils.getStringValue(getProperty(PropertyUtils.FONT_STYLE),font_style);
		}
		if(getProperty(PropertyUtils.FONT_SIZE)!=null){
			font_size=PropertyUtils.getIntValue(getProperty(PropertyUtils.FONT_SIZE),font_size);
		}
		
		if(getProperty(PropertyUtils.TEXT_ANTIALIASE)!=null){
			text_antialiase=PropertyUtils.getBooleanValue(getProperty(PropertyUtils.TEXT_ANTIALIASE),text_antialiase);
		}

		if(getProperty(PropertyUtils.TEXT_DRAW_LINE)!=null){
			text_draw_line=PropertyUtils.getBooleanValue(getProperty(PropertyUtils.TEXT_DRAW_LINE),text_draw_line);
		}
		
		if(getProperty(PropertyUtils.TEXT_DRAW_BORDER)!=null){
			text_draw_border=PropertyUtils.getBooleanValue(getProperty(PropertyUtils.TEXT_DRAW_BORDER),text_draw_border);
		}
		if(getProperty(PropertyUtils.TEXT_DRAW_SHADOW)!=null){
			text_draw_shadow=PropertyUtils.getBooleanValue(getProperty(PropertyUtils.TEXT_DRAW_SHADOW),text_draw_shadow);
		}
		if(getProperty(PropertyUtils.TEXT_LINE_COLOR)!=null){
			text_line_color=PropertyUtils.getColorValue(getProperty(PropertyUtils.TEXT_LINE_COLOR),text_line_color);
		}
		if(getProperty(PropertyUtils.TEXT_BORDER_COLOR)!=null){
			text_border_color=PropertyUtils.getColorValue(getProperty(PropertyUtils.TEXT_BORDER_COLOR),text_border_color);
		}
		if(getProperty(PropertyUtils.TEXT_SHADOW_COLOR)!=null){
			text_shadow_color=PropertyUtils.getColorValue(getProperty(PropertyUtils.TEXT_SHADOW_COLOR),text_shadow_color);
			//System.out.println("shadow:"+text_shadow_color);
		}
		if(getProperty(PropertyUtils.TEXT_BORDER_SIZE)!=null){
			text_border_size=PropertyUtils.getIntValue(getProperty(PropertyUtils.TEXT_BORDER_SIZE),text_border_size);
		}
		if(getProperty(PropertyUtils.TEXT_SHADOW_X)!=null){
			text_shadow_x=PropertyUtils.getIntValue(getProperty(PropertyUtils.TEXT_SHADOW_X),text_shadow_x);
		}
		if(getProperty(PropertyUtils.TEXT_SHADOW_Y)!=null){
			text_shadow_y=PropertyUtils.getIntValue(getProperty(PropertyUtils.TEXT_SHADOW_Y),text_shadow_y);
		}
		
		
		
		if(consume){
			consumeProperty();//remove all
		}
	}
	double currentTime=0;
	double line_fps=1;
	
	private boolean redownload;
	private FFMpegFLVParser fileInfoParser;
	//private Map videoInfos=new HashMap();
	private URLDownloader downloader;
	
	public void progressTime(){
		currentTime+=line_fps;
	}
	
	
	public DougaSystem parseTextDouga(File textd) throws IOException{
		String text=IOUtils.toString(new FileReader(textd));
		return parseTextDouga(text,textd.getParentFile());
	}
	
		public DougaSystem parseTextDouga(String text,File dir) throws IOException{
		inputDir=dir;
		dougaSystem = new DougaSystem();
		dougaSystem.setFfmpegPath(ffmpegPath);//very important
		
		videoList = new ArrayList<VideoData>();
		audioList = new ArrayList<AudioData>();
		itemList = new ArrayList<ItemData>();
		effectList = new ArrayList<EffectData>();
		
		DataLine[] dataLines=ParserUtils.parseDataLines(inputDir, text);
		
		
		//gather resources.
		//download FLV
		//download MP3 or images.
		//get resource
		int downloadItem=0;//for progress bar
		for (int i = 0; i < dataLines.length; i++) {
			if(dataLines[i] instanceof URLLine){
				URLLine urlLine=(URLLine)dataLines[i];
				if(YoutubeUtils.isYoutubeURL(urlLine.getLine())){
					//download..
					urlLine.setAbsolutePath(downloadedDir+"\\youtube.com\\"+YoutubeUtils.toFLVFileName(new URL(urlLine.getLine())));
					//set
				}else{
					urlLine.setAbsolutePath(DownloadUtils.toDownloadFile(downloadedDir, new URL(urlLine.getLine())).getAbsolutePath());
				}
				downloadItem++;
				
			}
			
			if(cancelling){
				
				return null;
			}
		}
		
		for (int i = 0; i < dataLines.length; i++) {
			if(dataLines[i] instanceof URLLine){
				URLLine urlLine=(URLLine)dataLines[i];
				
				//check file
				File saveFile=new File(urlLine.getAbsolutePath());
				if(saveFile.exists() && saveFile.length()>0 && !redownload){
					//don't download them.
				}else{
					if((youtubeDLPath==null || youtubeDLPath.length()==0 || !new File(youtubeDLPath).exists())&& YoutubeUtils.isYoutubeURL(urlLine.getLine())){
						DougaSystem.dougaLogger.error(Messages.getString("textdouga.need_youtubedl"));
						throw new IOException("youtube dl not found");
					}else{
					//log.warn(youtubeDLPath+","+(youtubeDLPath==null) +","+ YoutubeUtils.isYoutubeURL(urlLine.getLine()));
					DougaSystem.dougaLogger.info(Messages.getString("textdouga.start_download")+":"+urlLine.getLine());
					downloader = new URLDownloader();
					downloader.setPythonPath(pythonPath);
					downloader.setYoutubeDLPath(youtubeDLPath);
					saveFile.getParentFile().mkdirs();//for save dir.
					downloader.download(new URL(urlLine.getLine()), saveFile);//youtube-dl need directory
					DougaSystem.dougaLogger.info(Messages.getString("textdouga.finish_download")+":"+saveFile.getName());
					downloader=null;
					//TODO done progress.
					}
				}
				
				if(cancelling){
					
					return null;
				}
			}
		}
		
		
		
		//debug
		for (int i = 0; i < dataLines.length; i++) {
			System.out.println(dataLines[i]);
		}
		
		
		fileInfoParser = new FFMpegFLVParser(ffmpegPath);
		for (int i = 0; i < dataLines.length; i++) {
			if(dataLines[i] instanceof URLLine){
				URLLine urlLine=(URLLine) dataLines[i];
				parseURLLine(urlLine);
				consumeProperty();
			}else
			if(dataLines[i] instanceof PropertyLine){
				propertyLine=(PropertyLine) dataLines[i];
				parseProperty();
				//don't consume
			}else if(dataLines[i] instanceof ColorLine){
				parseColorLine((ColorLine)dataLines[i]);
				consumeProperty();
			}else if(dataLines[i] instanceof CommentLine){
				//just commnet
				log.info(dataLines[i]);
//				don't consume
			}else if(dataLines[i] instanceof EmptyLine){
				progressTime();
				consumeProperty();
			}else if(dataLines[i] instanceof FileLine){
				FileLine fileLine=(FileLine)dataLines[i];
				parseFileLine(fileLine);
				consumeProperty();
			}else if(dataLines[i] instanceof TextLine){
				parseTextLine((TextLine) dataLines[i]);
				consumeProperty();//
			}
		}
		
		//time check
		double totalVideo=0;
		double totalAudio=0;
		
		double totalItem=0;//TODO care item times.
		
		//add
		Iterator<VideoData> iter=videoList.iterator();
		while(iter.hasNext()){
			VideoData data=iter.next();
			dougaSystem.getVideoSystem().addVideoData(data);
			if(totalVideo!=DougaSystem.FOREEVER){
				double v=data.getTotalTime();
				if(v!=DougaSystem.FOREEVER){
					totalVideo+=v;
				}else{
					totalVideo=DougaSystem.FOREEVER;
				}
			}
		}
		
		Iterator<AudioData> iter2=audioList.iterator();
		while(iter2.hasNext()){
			AudioData data=iter2.next();
			dougaSystem.getAudioSystem().addAudioData(data);
			if(totalAudio!=DougaSystem.FOREEVER){
				double v=data.getTotalTime();
				if(v!=DougaSystem.FOREEVER){
					totalAudio+=v;
				}else{
					totalAudio=DougaSystem.FOREEVER;
				}
			}
		}
		
		Iterator<ItemData> iter3=itemList.iterator();
		while(iter3.hasNext()){
			dougaSystem.getVideoSystem().addItemData(iter3.next());
		}
		
		Iterator<EffectData> iter4=effectList.iterator();
		while(iter4.hasNext()){
			dougaSystem.getVideoSystem().addEffectData(iter4.next());
		}
		
		log.info("videoDatas:"+dougaSystem.getVideoSystem().getVideoDatas().length);
		VideoData[] videos=dougaSystem.getVideoSystem().getVideoDatas();
		for (int i = 0; i < videos.length; i++) {
			System.out.println("("+(i+1)+")"+videos[i]);
		}
		
		log.info("audioDatas:"+dougaSystem.getAudioSystem().getAudioDatas().length);
		AudioData[] audios=dougaSystem.getAudioSystem().getAudioDatas();
		for (int i = 0; i < audios.length; i++) {
			System.out.println("("+(i+1)+")"+audios[i]);
		}
		
		log.info("itemDatas:"+dougaSystem.getVideoSystem().getSortedItemDatas().length);
		ItemData[] items=dougaSystem.getVideoSystem().getSortedItemDatas();
		for (int i = 0; i < items.length; i++) {
			System.out.println("("+(i+1)+")"+items[i]);
		}
		
		
		log.info("videoLength:"+totalVideo);
		log.info("audioLength:"+totalAudio);
		if(totalVideo==0 && totalAudio==0){
			double lastTime=getLastItemTime();
			if(lastTime>0){//valid item
				ColorVideoData data=new ColorVideoData(0);
				data.setDuration(DougaSystem.FOREEVER);
				dougaSystem.getVideoSystem().addVideoData(data);
				totalVideo=DougaSystem.FOREEVER;
			}
		}
		

		if(totalVideo==DougaSystem.FOREEVER && totalAudio==DougaSystem.FOREEVER){
			double lastTime=getLastItemTime();
			if(lastTime==0){
				throw new IOException("audio & video both play forever");
				}
			else{
				dougaSystem.getVideoSystem().setMaxTime(lastTime);
				dougaSystem.getAudioSystem().setMaxTime(lastTime);
			}
			
		}
	
		else if(totalVideo==DougaSystem.FOREEVER){
			if(totalAudio==0){
				double lastTime=getLastItemTime();
				if(lastTime==0){
					throw new IOException("forever play video need audio");
					}
				else{
					dougaSystem.getVideoSystem().setMaxTime(lastTime);
				}
			
			}else{
			dougaSystem.getVideoSystem().setMaxTime(totalAudio);
			}
		}
		
		else if(totalAudio==DougaSystem.FOREEVER){
			if(totalVideo==0){
				double lastTime=getLastItemTime();
				if(lastTime==0){
					throw new IOException("forever play audio need video");
					}
				else{
					//insert default black
					ColorVideoData data=new ColorVideoData(0);
					data.setDuration(lastTime);
					dougaSystem.getVideoSystem().addVideoData(data);
					dougaSystem.getAudioSystem().setMaxTime(lastTime);
				}
				
				}
			else{
			dougaSystem.getAudioSystem().setMaxTime(totalVideo);
			}
		}
		
		//set effect time
		
		Iterator<VideoData> tmpIter=videoList.iterator();
		double currentTime=0;
		double fps=dougaSystem.getVideoSystem().getDougaPreference().getFps();
		LOOP:while(tmpIter.hasNext()){
			VideoData data=tmpIter.next();
			EffectableVideoData effectable=null;
			if(data instanceof EffectableVideoData){
				effectable=(EffectableVideoData)data;
			}
			
			if(effectable!=null && effectable.getStartEffect()!=null){
				int keyFrame=(int) (currentTime*fps+1);
				effectable.getStartEffect().setKeyFrame(keyFrame);
				System.out.println("start:"+keyFrame);
			}
			
			double v=data.getTotalTime();
			if(v!=DougaSystem.FOREEVER){
				int frames=(int) (v*fps);
				System.out.println("v="+v+",fps="+dougaSystem.getVideoSystem().getDougaPreference().getFps()+" = "+(v*dougaSystem.getVideoSystem().getDougaPreference().getFps()));
				System.out.println("frames="+frames+","+data);
				currentTime+=v;
				if(effectable!=null && effectable.getEndEffect()!=null){
					int keyFrame=(int) (currentTime*fps+1);
					effectable.getEndEffect().setKeyFrame(keyFrame);
					System.out.println("end:"+(keyFrame));
				}
				
				
			}else{
				//FOREVER
				double duration=dougaSystem.getVideoSystem().getMaxTime()-currentTime;
				int keyFrame=(int) (duration*fps);
				
				if(effectable!=null && effectable.getEndEffect()!=null){
					effectable.getEndEffect().setKeyFrame(keyFrame);
					System.out.println("end:"+(keyFrame));
				}
				break LOOP;//no more videos.
			}
			
		}
		
		log.info("effectDatas:"+dougaSystem.getVideoSystem().getEffectDatas().length);
		EffectData[] effects=dougaSystem.getVideoSystem().getEffectDatas();
		for (int i = 0; i < effects.length; i++) {
			System.out.println("("+(i+1)+")"+effects[i]);
		}
		
		//System.exit(0);
		
		//can handel time?
		//safety zone.
		if(totalVideo>60*60 || totalAudio>60*60){
			throw new IOException("audio or video is too long ,now support under 30 minute for safety");
		}
		
		
		return dougaSystem;
	}
		/**
		 * 
		 * @param line
		 * color property is
		 * start,duration,transparent
		 */
	private double getLastItemTime(){
		double last=0;
		Iterator<ItemData> iter3=itemList.iterator();
		while(iter3.hasNext()){
			ItemData data=iter3.next();
			last=Math.max(last, data.getLastTime());
			//dougaSystem.getVideoSystem().addItemData();
		}
		return last;
	}
	private void parseColorLine(ColorLine line) {
		double start=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.START),currentTime);
		double duration=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DURATION),getDefaultDuration());
		float transparent=PropertyUtils.getPersentFloatValue(getProperty(PropertyUtils.TRASNPARENT), default_color_transparent);
		
		ColorItem item=new ColorItem(line.getColor(),transparent);
		item.setStartTime(start);
		item.setDuration(duration);
		itemList.add(item);
		
		processProgressTime();
	}
	
	
	private void processProgressTime(){
		boolean noprogress=PropertyUtils.getBooleanValue(getProperty(PropertyUtils.NO_PROGRESS));
		//the set stat property line is absolute and ignore
		double start=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.START),-1);
		if(!noprogress && start<0){
			progressTime();
		}
	}
	
	public void parseURLLine(URLLine urlLine) throws IOException{
		String path=urlLine.getAbsolutePath();
		int type=ParserUtils.getFileType(urlLine.getAbsolutePath());
		if(type==ParserUtils.FILE_VIDEO){
			parseVideoFile(new File(path));
		}else if(type==ParserUtils.FILE_AUDIO){
			parseAudioFile(new File(path));
		}else if(type==ParserUtils.FILE_IMAGE){
			parseImageFile(new File(path));
			
			processProgressTime();
		}
	}
	
	public void parseAudioFile(File file){
		double start=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.START),0);
		double duration=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DURATION),0);
		int loop=PropertyUtils.getIntValue(getProperty(PropertyUtils.LOOP), 0);
		
		
		//TODO mediaInfo
		FFMpegFileInfomation info=parseFileInfomation(file);
		
		FileAudioData adata=new FileAudioData(file.getAbsolutePath());
		adata.setStartTime(start);
		adata.setDuration(duration);
		adata.setLoop(loop);
		
		adata.setLogicalTime(FFMpegUtils.timeToDouble(info.getDuration()));
		audioList.add(adata);
	}
	
	private Map<String,FFMpegFileInfomation> fileInfoMap=new HashMap<String,FFMpegFileInfomation>();
	
	private FFMpegFileInfomation parseFileInfomation(File file){
		FFMpegFileInfomation info=fileInfoMap.get(file.getAbsolutePath());
		if(info==null){
			info=fileInfoParser.parseFile(file);
			fileInfoMap.put(file.getAbsolutePath(), info);
		}
		return info;
	}
	public void parseVideoFile(File file) throws IOException{
		double start=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.START),0);
		double duration=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DURATION),0);
		int loop=PropertyUtils.getIntValue(getProperty(PropertyUtils.LOOP), 0);
		
		
		boolean addVideo=true;
		boolean addAudio=true;	//if it's has
		
		String v=getProperty(PropertyUtils.NOVIDEO);
		String a=getProperty(PropertyUtils.NOAUDIO);
		if(a!=null){
			addAudio=false;
		}
		
		if(v!=null){
			addVideo=false;
		}
		
		//anytime add video
		FFMpegFileInfomation info=parseFileInfomation(file);
		
		
		FileVideoData fdata=null;
		if(addVideo){
			if(!info.isHaveVideo()){
				System.out.println(fileInfoParser.getLogText());
				throw new IOException("no video wrong file:");
				
			}
		
		fdata=new FileVideoData(file.getAbsolutePath());
		
		fdata.setStartTime(start);
		fdata.setDuration(duration);
		fdata.setLoop(loop);
		videoList.add(fdata);
		fdata.setLogicalTime(FFMpegUtils.timeToDouble(info.getDuration()));
		
		parseVideoEffect(fdata);
		}
		
		if(addAudio){
		if(info.isHaveAudio()){
			FileAudioData adata=new FileAudioData(file.getAbsolutePath());
			adata.setStartTime(start);
			adata.setDuration(duration);
			adata.setLoop(loop);
			
			adata.setLogicalTime(FFMpegUtils.timeToDouble(info.getDuration()));
			audioList.add(adata);
			
			if(fdata!=null){
				fdata.setAudioData(adata);//this means synch
			}
		}else{
			log.warn("this video has no audio:"+file.getAbsolutePath());
		}
		}
	}
	private void parseVideoEffect(FileVideoData fdata) {
		int effect=PropertyUtils.getIntValue(getProperty(PropertyUtils.EFFECT), 0);
		int start_effect=PropertyUtils.getIntValue(getProperty(PropertyUtils.START_EFFECT),0);
		int end_effect=PropertyUtils.getIntValue(getProperty(PropertyUtils.END_EFFECT), 0);
		
		double effect_before=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.EFFECT_BEFORE),0.2);
		double effect_after=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.EFFECT_AFTER),0.2);
		double effect_full=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.EFFECT_FULL),0.1);
		
		
		int color=PropertyUtils.getColorValue(getProperty(PropertyUtils.EFFECT_COLOR), 0);//default is black
		File imageFile=PropertyUtils.getFileValue(getProperty(PropertyUtils.EFFECT_IMAGE),inputDir, null);
		BufferedImage image=null;
		if(imageFile!=null){
			try {
				ImageIO.read(imageFile);
			} catch (IOException e) {
			
				e.printStackTrace();
			}
		}
		
		if(effect>0){
			VideoEffect videoEffect=null;
			switch(effect){
			case 1:		//frame
				//no frame in effect all
				break;
			case 2:		//color
				videoEffect=new FillColorEffect(color);
				break;
			case 3:		//image
				if(image!=null){
					videoEffect=new FillImageEffect(image);
				}
				break;
			}
			if(videoEffect!=null){
				videoEffect.setMode(DougaSystem.FOREEVER);
				if(!(videoEffect instanceof FrameImageEffect)){	//FrameImageEffect don't need.
					videoEffect.setBeforeTime(effect_before);
					videoEffect.setAfterTime(effect_after);
					videoEffect.setFullEffectTime(effect_full);
					}
				effectList.add(videoEffect);
			}
		}else if(effect<0){
			//audio
			//TODO
		}
		
		if(start_effect>0){
			
			VideoEffect videoEffect=null;
			switch(start_effect){
			case 1:		//frame
				//no frame in effect all
				videoEffect=new FrameImageEffect(false,effect_after);
				break;
			case 2:		//color
				videoEffect=new FillColorEffect(color);
				break;
			case 3:		//image
				if(image!=null){
					videoEffect=new FillImageEffect(image);
				}
				break;
			}
			if(videoEffect!=null){
				if(!(videoEffect instanceof FrameImageEffect)){	//FrameImageEffect don't need.
					videoEffect.setBeforeTime(effect_before);
					videoEffect.setAfterTime(effect_after);
					videoEffect.setFullEffectTime(effect_full);
					}
				fdata.setStartEffect(videoEffect);
				effectList.add(videoEffect);
			}
		}else if(start_effect<0){
			//audio
			//TODO
		}
		
		if(end_effect>0){
			VideoEffect videoEffect=null;
			switch(end_effect){
			case 1:		//frame
				//no frame in effect all
				//now it didn't support
				//videoEffect=new FrameImageEffect(true,effect_before);
				break;
			case 2:		//color
				videoEffect=new FillColorEffect(color);
				break;
			case 3:		//image
				if(image!=null){
					videoEffect=new FillImageEffect(image);
				}
				break;
			}
			if(videoEffect!=null){
				if(!(videoEffect instanceof FrameImageEffect)){	//FrameImageEffect don't need.
				videoEffect.setBeforeTime(effect_before);
				videoEffect.setAfterTime(effect_after);
				videoEffect.setFullEffectTime(effect_full);
				}
				fdata.setEndEffect(videoEffect);
				effectList.add(videoEffect);
			}
		}else if(end_effect<0){
			//audio
			//TODO
		}
		
	}
	public void parserDirectoryFile(File dir){

		
		int loop=PropertyUtils.getIntValue(getProperty(PropertyUtils.LOOP), 1);
		if(loop<=0){
			log.warn("wrong loop:"+getProperty(PropertyUtils.LOOP));
			loop=1;
		}
		double start=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.START),currentTime);
		double duration=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DURATION),1);//TODO make default?
		double wait=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.WAIT),0.1);//TODO default
		
		double fadein=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.FADEIN),0.2);
		double fadeout=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.FADEOUT),0.2);
		
		String list[]=dir.list();
		double time=start;
		double transparent=PropertyUtils.getPersentDoubleValue(getProperty(PropertyUtils.TRASNPARENT),1.0);//TODO default
		int added=0;
		if(list!=null){
			ItemLocationAndAlign ia=new ItemLocationAndAlign(0,0,0,0,0,ItemData.CENTER,ItemData.CENTER,true);
			ia.loadProperty();
			
			for(int i=0;i<loop;i++){
			for (int j = 0; j < list.length; j++) {
				if(ParserUtils.getFileType(list[j])==ParserUtils.FILE_IMAGE){
					//show slide show.
					ImageItem item=createImageItem(new File(dir,list[j]),1);//dir didn't loop
					
					ia.setUpItem(item);
					
					item.setStartTime(time);
					item.setDuration(duration);
					item.setTransparent((float) transparent);
					item.setFadeInTime(fadein);
					item.setFadeOutTime(fadeout);
					
					itemList.add(item);
					added++;
					log.info("start="+time+" duration="+duration+" img="+item.getInputPath());
					time+=duration+wait;
				}
			}
			}
		}else{
			log.warn("list null:"+dir);
		}
		log.info("add dir images "+added+ " as item overray="+transparent);
	
	
	}
	public void parseFileLine(FileLine fileLine) throws IOException{
		int type=ParserUtils.getFileType(fileLine.getAbsolutePath());
		if(type==ParserUtils.FILE_VIDEO){
			parseVideoFile(fileLine.getFile());
		}else if(type==ParserUtils.FILE_DIRECTORY){
			parserDirectoryFile(fileLine.getFile());
		}else if(type==ParserUtils.FILE_AUDIO){
			parseAudioFile(fileLine.getFile());
		}else if(type==ParserUtils.FILE_IMAGE){
			parseImageFile(fileLine.getFile());
		}
		consumeProperty();
	}
	
	
	private ImageItem createImageItem(File imageFile,int loop){
		if(imageFile.getName().toLowerCase().endsWith(".gif")){
			GifAnimeItem item=new GifAnimeItem();
			item.setLoop(loop);
			item.setInputPath(imageFile.getAbsolutePath());
			return item;
		}else{
			ImageItem item=new ImageItem();
			item.setInputPath(imageFile.getAbsolutePath());
			return item;
		}
	}
	private double getDefaultDuration(){
		double default_d=line_fps;
		if(line_duration>0){
			default_d=line_duration;
		}
		return default_d;
	}
	private void parseImageFile(File file) {
		double start=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.START),-1);
		
		
		double duration=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DURATION),getDefaultDuration());
		
		double fadein=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.FADEIN),default_image_fadein);	
		double fadeout=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.FADEOUT),default_image_fadeout);
		double transparent=PropertyUtils.getPersentDoubleValue(getProperty(PropertyUtils.TRASNPARENT),1.0);//TODO default_image_transparent
		
		int loop=PropertyUtils.getIntValue(getProperty(PropertyUtils.LOOP), 1);
		
		ImageItem item=createImageItem(file,loop);
		if(start>=0){
			item.setStartTime(start);
		}else{
			item.setStartTime(currentTime);
		}
		
		

		ItemLocationAndAlign ia=new ItemLocationAndAlign(0,0,0,default_image_width,default_image_height,ItemData.CENTER,ItemData.CENTER,true);
		ia.loadProperty();
		ia.setUpItem(item);
	//	setItemLocation(item,0,0,0,0,1); //image little bit draw back.
		
		//setItemAlignValign(item,ItemData.CENTER,ItemData.CENTER);
		

		item.setDuration(duration);//duration 4?
		item.setTransparent((float) transparent);
		item.setFadeInTime(fadein);
		item.setFadeOutTime(fadeout);
		
		itemList.add(item);
		
		
		processProgressTime();
		
	}
	/*
	private void setItemAlignValign(AbstractItem item,int defaultAlign,int defaultValign){
		int align=defaultAlign;
		int valign=defaultValign;
		
		if(getProperty(PropertyUtils.X)!=null){
			align=ImageItem.NONE;
		}
		if(getProperty(PropertyUtils.Y)!=null){
			valign=ImageItem.NONE;
		}
		String avalue=PropertyUtils.getStringValue(getProperty(PropertyUtils.ALIGN),"");
		if(avalue.equals(PropertyUtils.ALIGN_CENTER)){
			align=ImageItem.CENTER;
		}else if(avalue.equals(PropertyUtils.ALIGN_LEFT)){
			align=ImageItem.LEFT;
		}else if(avalue.equals(PropertyUtils.ALIGN_RIGHT)){
			align=ImageItem.RIGHT;
		}
		
		String vvalue=PropertyUtils.getStringValue(getProperty(PropertyUtils.VALIGN),"");
		if(vvalue.equals(PropertyUtils.VALIGN_CENTER)){
			valign=ImageItem.MIDDLE;
		}else if(vvalue.equals(PropertyUtils.VALIGN_MIDDLE)){
			valign=ImageItem.MIDDLE;
		}else if(vvalue.equals(PropertyUtils.VALIGN_TOP)){
			valign=ImageItem.TOP;
		}else if(vvalue.equals(PropertyUtils.VALIGN_BOTTOM)){
			valign=ImageItem.BOTTOM;
		}
		
		item.setAlign(align);
		item.setValign(valign);
	}*/
	public void parseTextLine(TextLine textline){
		double default_d=line_fps;
		if(line_duration>0){
			default_d=line_duration;
		}
		
		double start=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.START),-1);
		double duration=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.DURATION),default_d);
		
		double fadein=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.FADEIN),default_text_fadein);
		double fadeout=PropertyUtils.getDoubleValue(getProperty(PropertyUtils.FADEOUT),default_text_fadeout);
		boolean noprogress=PropertyUtils.getBooleanValue(getProperty(PropertyUtils.NO_PROGRESS));
		
		TextItem item=new TextItem(textline.getText());
		if(start>=0){
			item.setStartTime(start);
			noprogress=true;//dont progress when time is absolute
		}else{
			item.setStartTime(currentTime);
		}
	
		item.setDuration(duration);
		item.setFadeInTime(fadein);
		item.setFadeOutTime(fadeout);
		
		
		//TODO
		//font
		
		//decoration
		
		//location
		//setItemLocation(item,0,0,0,0,0);
		
		//layout
		//setItemAlignValign(item,ItemData.CENTER,ItemData.BOTTOM);

		ItemLocationAndAlign ia=new ItemLocationAndAlign(0,0,0,0,0,ItemData.CENTER,ItemData.BOTTOM,true);
		ia.loadProperty();
		ia.setUpItem(item);
		
		setUpTextDecoration(item);
		
		itemList.add(item);
		if(!noprogress){
			progressTime();
		}
	}
	
	public void setUpTextDecoration(TextItem item){
		int fontStyle=Font.PLAIN;
		if(font_style.equals(PropertyUtils.FONT_STYLE_BOLD)){
			fontStyle=Font.BOLD;
		}else if(font_style.equals(PropertyUtils.FONT_STYLE_ITALIC)){
			fontStyle=Font.ITALIC;
		}else if(font_style.equals(PropertyUtils.FONT_STYLE_BOLD_ITALIC)){
			fontStyle=Font.BOLD|Font.ITALIC;
		}
		Font font=new Font(font_name,fontStyle,font_size);
		item.setFont(font);
		
		DecoratedShapePainter decoration=item.getDecoratedShapePainter();
		decoration.setAntialiase(text_antialiase);
		decoration.setAntialiaseShadow(text_antialiase);
		decoration.setFillColor(text_line_color);
		decoration.setLineColor(text_border_color);
		decoration.setLineSize(text_border_size);
		decoration.setShadowColor(text_shadow_color);
		decoration.setShadowOffsetX(text_shadow_x);
		decoration.setShadowOffsetY(text_shadow_y);
		
		decoration.setFill(text_draw_line);
		decoration.setLine(text_draw_border);
		decoration.setShadow(text_draw_shadow);
	}
	/*
	private void setItemLocation(AbstractItem item,int dx, int dy, int dw, int dh, int dz) {
		int x=PropertyUtils.getIntValue(getProperty(PropertyUtils.X),dx);
		int y=PropertyUtils.getIntValue(getProperty(PropertyUtils.Y),dy);
		
		int width=PropertyUtils.getIntValue(getProperty(PropertyUtils.WIDTH),dw);
		int height=PropertyUtils.getIntValue(getProperty(PropertyUtils.HEIGHT),dh);
		
		int z=PropertyUtils.getIntValue(getProperty(PropertyUtils.Z),dz);
		item.setBounds(x,y,width,height);
		item.setZ(z);	
	}*/
	
	public class ItemLocationAndAlign{
		private int x;
		private int y;
		private int z;
		private int width;
		private int height;
		private int align;
		private int valign;
		private boolean keepAspect;
		
		
		
		public boolean isKeepAspect() {
			return keepAspect;
		}
		public void setKeepAspect(boolean keepAspect) {
			this.keepAspect = keepAspect;
		}
		/**
		 * 
		 * @param x
		 * @param y
		 * @param z
		 * @param width
		 * @param height
		 * @param align
		 * @param valign
		 * @param keepAspect
		 */
		public ItemLocationAndAlign(int x,int y,int z,int width,int height,int align,int valign,boolean keepAspect){
			this.x=x;
			this.y=y;
			this.z=z;
			this.width=width;
			this.height=height;
			this.align=align;
			this.valign=valign;
			this.keepAspect=keepAspect;
		}
		public void setUpItem(AbstractItem item){
			item.setBounds(x,y,width,height);
			item.setZ(z);
			item.setKeepAspect(keepAspect);
			
			item.setAlign(align);
			item.setValign(valign);
			
		}
		public void loadProperty(){
			x=PropertyUtils.getIntValue(getProperty(PropertyUtils.X),this.x);
			y=PropertyUtils.getIntValue(getProperty(PropertyUtils.Y),this.y);
			
			width=PropertyUtils.getIntValue(getProperty(PropertyUtils.WIDTH),this.width);
			height=PropertyUtils.getIntValue(getProperty(PropertyUtils.HEIGHT),this.height);
			
			z=PropertyUtils.getIntValue(getProperty(PropertyUtils.Z),this.z);
			
			keepAspect=PropertyUtils.getBooleanValue(getProperty(PropertyUtils.KEEP_ASPECT),keepAspect);
			
			
			if(getProperty(PropertyUtils.X)!=null){
				align=ImageItem.NONE;
			}
			if(getProperty(PropertyUtils.Y)!=null){
				valign=ImageItem.NONE;
			}
			
			String avalue=PropertyUtils.getStringValue(getProperty(PropertyUtils.ALIGN),"");
			if(avalue.equals(PropertyUtils.ALIGN_CENTER)){
				align=ImageItem.CENTER;
			}else if(avalue.equals(PropertyUtils.ALIGN_LEFT)){
				align=ImageItem.LEFT;
			}else if(avalue.equals(PropertyUtils.ALIGN_RIGHT)){
				align=ImageItem.RIGHT;
			}
			
			String vvalue=PropertyUtils.getStringValue(getProperty(PropertyUtils.VALIGN),"");
			if(vvalue.equals(PropertyUtils.VALIGN_CENTER)){
				valign=ImageItem.MIDDLE;
			}else if(vvalue.equals(PropertyUtils.VALIGN_MIDDLE)){
				valign=ImageItem.MIDDLE;
			}else if(vvalue.equals(PropertyUtils.VALIGN_TOP)){
				valign=ImageItem.TOP;
			}else if(vvalue.equals(PropertyUtils.VALIGN_BOTTOM)){
				valign=ImageItem.BOTTOM;
			}
		}
		public int getAlign() {
			return align;
		}
		public void setAlign(int align) {
			this.align = align;
		}
		public int getHeight() {
			return height;
		}
		public void setHeight(int height) {
			this.height = height;
		}
		public int getValign() {
			return valign;
		}
		public void setValign(int valign) {
			this.valign = valign;
		}
		public int getWidth() {
			return width;
		}
		public void setWidth(int width) {
			this.width = width;
		}
		public int getX() {
			return x;
		}
		public void setX(int x) {
			this.x = x;
		}
		public int getY() {
			return y;
		}
		public void setY(int y) {
			this.y = y;
		}
		public int getZ() {
			return z;
		}
		public void setZ(int z) {
			this.z = z;
		}
	
	
	}
	public void consumeProperty(){
		propertyLine=null;
	}
	public String getProperty(String key){
		if(propertyLine==null){
			return null;
		}else{
			return propertyLine.getValue(key);
		}
	}
	public boolean isCancelling() {
		return cancelling;
	}
	public void setCancelling(boolean cancelling) {
		this.cancelling = cancelling;
		if(cancelling && downloader!=null){
			try {
				downloader.cancel();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
